using System.CommandLine;
using System.Text.Json;
using Grpc.Net.Client;
using CSharpAnalyzer.AnalyzerService.Grpc;

namespace CSharpAnalyzer.AnalyzerCli;

/// <summary>
/// CLI wrapper for the C# Analyzer Service
/// </summary>
class Program
{
    static async Task<int> Main(string[] args)
    {
        var rootCommand = new RootCommand("C# Analyzer CLI - Analyzes C# solutions using Roslyn");

        var solutionOption = new Option<string>(
            name: "--solution",
            description: "Path to the .sln file to analyze")
        {
            IsRequired = true
        };
        solutionOption.AddAlias("-s");

        var outputOption = new Option<string>(
            name: "--output",
            description: "Output directory for JSON files (default: current directory)",
            getDefaultValue: () => Directory.GetCurrentDirectory());
        outputOption.AddAlias("-o");

        var serverOption = new Option<string>(
            name: "--server",
            description: "gRPC server address",
            getDefaultValue: () => "http://localhost:5000");

        var projectsOption = new Option<string[]>(
            name: "--projects",
            description: "Specific project names to analyze (optional)")
        {
            AllowMultipleArgumentsPerToken = true
        };
        projectsOption.AddAlias("-p");

        rootCommand.AddOption(solutionOption);
        rootCommand.AddOption(outputOption);
        rootCommand.AddOption(serverOption);
        rootCommand.AddOption(projectsOption);

        rootCommand.SetHandler(
            AnalyzeSolutionAsync,
            solutionOption,
            outputOption,
            serverOption,
            projectsOption);

        return await rootCommand.InvokeAsync(args);
    }

    static async Task<int> AnalyzeSolutionAsync(
        string solutionPath,
        string outputDir,
        string serverAddress,
        string[] projects)
    {
        try
        {
            Console.WriteLine($"C# Analyzer CLI");
            Console.WriteLine($"Solution: {solutionPath}");
            Console.WriteLine($"Output: {outputDir}");
            Console.WriteLine($"Server: {serverAddress}");

            if (!File.Exists(solutionPath))
            {
                Console.WriteLine($"Error: Solution file not found: {solutionPath}");
                return 1;
            }

            if (!Directory.Exists(outputDir))
            {
                Directory.CreateDirectory(outputDir);
                Console.WriteLine($"Created output directory: {outputDir}");
            }

            // Create gRPC channel and client
            using var channel = GrpcChannel.ForAddress(serverAddress);
            var client = new Grpc.AnalyzerService.AnalyzerServiceClient(channel);

            Console.WriteLine("Connecting to analyzer service...");

            // Create request
            var request = new SolutionRequest
            {
                SolutionPath = Path.GetFullPath(solutionPath)
            };

            if (projects != null && projects.Length > 0)
            {
                request.ProjectNames.AddRange(projects);
                Console.WriteLine($"Analyzing specific projects: {string.Join(", ", projects)}");
            }

            // Call the service
            Console.WriteLine("Analyzing solution...");
            var response = await client.AnalyzeSolutionAsync(request);

            // Check for errors
            if (response.Errors.Count > 0)
            {
                Console.WriteLine("\nErrors encountered:");
                foreach (var error in response.Errors)
                {
                    Console.WriteLine($"  - {error}");
                }
            }

            // Process results
            Console.WriteLine($"\nAnalysis complete!");
            Console.WriteLine($"Solution: {response.SolutionName}");
            Console.WriteLine($"Projects analyzed: {response.Projects.Count}");

            // Write output files
            var solutionOutputDir = Path.Combine(outputDir, response.SolutionName);
            if (!Directory.Exists(solutionOutputDir))
            {
                Directory.CreateDirectory(solutionOutputDir);
            }

            foreach (var project in response.Projects)
            {
                Console.WriteLine($"\nProject: {project.Name}");
                Console.WriteLine($"  Documents: {project.Documents.Count}");

                var projectOutputDir = Path.Combine(solutionOutputDir, project.Name);
                if (!Directory.Exists(projectOutputDir))
                {
                    Directory.CreateDirectory(projectOutputDir);
                }

                foreach (var document in project.Documents)
                {
                    var outputFileName = Path.GetFileNameWithoutExtension(document.Name) + ".json";
                    var outputPath = Path.Combine(projectOutputDir, outputFileName);

                    // Pretty-print the JSON
                    var jsonDoc = JsonDocument.Parse(document.SyntaxJson);
                    var prettyJson = JsonSerializer.Serialize(jsonDoc, new JsonSerializerOptions
                    {
                        WriteIndented = true
                    });

                    await File.WriteAllTextAsync(outputPath, prettyJson);
                    Console.WriteLine($"    - {document.Name} -> {outputFileName}");
                }
            }

            Console.WriteLine($"\nOutput written to: {solutionOutputDir}");
            return response.Errors.Count > 0 ? 1 : 0;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
            Console.WriteLine($"Stack trace: {ex.StackTrace}");
            return 1;
        }
    }
}
